
//-----------------------------------------------------------------------------
// Title       : 	Stack testbench module implementation
// Author      : 	Andrei Stan
// Created     : 	31/05/2011
// Description : 	This module implements a testbench for the stack module.
//-----------------------------------------------------------------------------

`include "stack_defs.v"

`timescale 1ns / 1ps

module tb_stack;

parameter CLK_PERIOD	= 10;

parameter DATA_WIDTH	=	12;
parameter SP_WIDTH		=	4;
parameter STACK_DEPTH	= 9;

reg clk;
reg [DATA_WIDTH-1:0] i_data;
reg [`STACK_CMD_WIDTH-1:0] i_cmd;

wire [DATA_WIDTH-1:0] o_data;
wire o_full;

//-----------------------------------------------------------------------------
// device instantioation and device parameters assignment
//-----------------------------------------------------------------------------
defparam stack_DUT.DATA_WIDTH		= DATA_WIDTH;
defparam stack_DUT.SP_WIDTH 		= SP_WIDTH;
defparam stack_DUT.STACK_DEPTH 	= STACK_DEPTH;

stack stack_DUT( 
	.clk(clk),
	.i_data(i_data),
	.o_data(o_data),
	.i_cmd(i_cmd),
	.o_full(o_full)
);

//-----------------------------------------------------------------------------
// clock generation specification
//-----------------------------------------------------------------------------
always
	#(CLK_PERIOD/2) clk = ~clk;

//-----------------------------------------------------------------------------
// the testbench specification
//-----------------------------------------------------------------------------
initial 
begin
	clk = 0;
	i_data = 0;
	i_cmd = `STACK_CMD_HOLD; 

	#10
	cmd_set_and_hold( `STACK_CMD_RESET );
   
	cmd_push_values( 12, 0 );

	cmd_pop_values( 15 );

	cmd_push_values( 5, 5 );

	cmd_pop_values( 3 );

	cmd_push_values( 8, 10 );

	cmd_pop_values( 10 );
		   
	#20	
		$finish;
end

//-----------------------------------------------------------------------------
// Name:			: data_set
// Description: task that puts a given value on the input data bus of the stack
// Inputs			: data	- the data value to be written on the input data bus 
// Outputs		: none
//-----------------------------------------------------------------------------
task data_set;
   input [DATA_WIDTH-1:0] data;
begin
   i_data = data;
end
endtask

//-----------------------------------------------------------------------------
// Name:			: cmd_set_and_hold
// Description: task that generates/executes a given command and then a HOLD
//						: command
// Inputs			: cmd		- the command that will be generated/executed
// Outputs		: none
//-----------------------------------------------------------------------------
task cmd_set_and_hold;
	input [`STACK_CMD_WIDTH-1:0] cmd;
begin
	i_cmd = cmd;
#CLK_PERIOD
	i_cmd = `STACK_CMD_HOLD;
end
endtask

//-----------------------------------------------------------------------------
// Name:			: cmd_push_values
// Description: task that generates/executes a given number of PUSH operations
// Inputs			: ops_no			- the number of operations
//						: init_value 	- initial value that is pushed onto the stack
//														the following values are one greater than the 
//														previous one 
// Outputs		: none
// Warning		:	Be careful at the ops_no range!
//-----------------------------------------------------------------------------
task cmd_push_values;
	input integer ops_no;
	input [DATA_WIDTH-1:0] init_value;
	reg [ DATA_WIDTH-1:0 ] data;
begin
	data = init_value;
	repeat( ops_no )
		begin
		#10
			data_set( data );
			cmd_set_and_hold( `STACK_CMD_PUSH );
			data = data + 1;
		end
end
endtask

//-----------------------------------------------------------------------------
// Name:			: cmd_pop_values
// Description: task that generates/executes a given number of POP operations
// Inputs			: ops_no	- the number of operations
// Outputs		: none
// Warning		:	Be careful at the ops_no range!
//-----------------------------------------------------------------------------
task cmd_pop_values;
	input integer ops_no;
begin
	repeat( ops_no )
		begin
		#10
			cmd_set_and_hold( `STACK_CMD_POP );
		end
end
endtask
	
endmodule
